import {Spin} from "antd";
import React, {FC, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from "react";
import {getFormView, getFormViewList} from "../../services/ViewService";
import {createParams, getObjByRule, isString, tryFunction, tryFunctionAsync} from "../../utils";
import "./css/CreateModal.less";
import {addOkModal, closeModal} from "../../services/ModalService";
import {AxiosGet, AxiosSer} from "../../services/HttpService";
import useStateRef from "../../customUse/useStateRef";
import useThrottle from "../../customUse/useThrottle";
import Config from "../../Config";
import BaseForm from "../../module/form/BaseForm.tsx";

interface CreateModalProps {
    className?: string,
    menuId: string,
    isDisabledForm: boolean,
    modalKey?: string,
    url: string,
    view: string | any[],
    init: any,
    type: string,
    extend?: any,
    defaultValue?: any,
    parentKey?: string | undefined,
    flowData?: any,
    method?: string,
    dataSource: string,
    formItemLayout?: string,
    otherCommonKeys?: string[],
    getInitData?: Function,
    beforeSubmit?: Function,
    onValuesChange?: Function
    formatFormView?: Function,
    onRemoveView?: Function,
    unUrlIsFinish?: boolean,
    children?: any,
    isMessBool?: any
}

const CreateModal: FC<CreateModalProps> = (props) => {
    const fromRef = useRef();
    const viewRef = useRef([]);
    const linkageRef = useRef({});

    const [editData, setEditData] = useState<any>({}),
        [view, setView] = useStateRef([], viewRef),
        [loading, setLoading] = useState<boolean>(false);

    const isCreate: Function = useCallback(() => {
        return props.type === "create";
    }, [props.type]);

    const isEdit: Function = useCallback(() => {
        return props.type === "edit";
    }, [props.type]);

    const isCopy: Function = useCallback(() => {
        return props.type === "copy";
    }, [props.type]);

    const onValuesChange: Function = useCallback(async (changedValues: any, allValues: any) => {
        await tryFunctionAsync(async () => {
            linkageRef.current.valueChangeFormatView && (await linkageRef.current.valueChangeFormatView.call(null, allValues, fromRef.current.updateView));
        })
        props.onValuesChange && props.onValuesChange(changedValues, allValues, fromRef.current.updateView);
    }, [props.onValuesChange]);

    const beforeSubmit: Function = useCallback(async (params: any, view: any) => {
        if (props.beforeSubmit) {
            return props.beforeSubmit(params, view);
        } else if (linkageRef.current.beforeSubmit) {
            return await linkageRef.current.beforeSubmit.call(null, params, view);
        }
        return params;
    }, [props.beforeSubmit, props.flowData]);

    const getInitData: Function = useCallback(async () => {
        let {flowData, getUrl, getParams = {}, defaultValue = {}}: {
            flowData: any,
            getUrl: string,
            getParams: any,
            defaultValue: any
        } = props;
        let editData = !isCreate() && flowData ? {...defaultValue, ...flowData[0]} : defaultValue;
        editData = createParams(editData, {...props, expandAttrKey: ""});
        if (!isCreate() && getUrl) {
            let params = getObjByRule(editData, getParams)
            editData = (await AxiosGet(getUrl, {
                ...params,
                id: editData.id,
                [Config.axiosSerMenuKey]: props.menuId
            })).data;
        }
        if (isCopy()) {
            delete editData.id;
        }
        if (props.getInitData) {
            return await props.getInitData(editData);
        }
        return editData;
    }, [props.getInitData, props.menuId]);

    const onOk: Function = useThrottle(async () => {
        const values: any = await fromRef.current.validateFields();
        let params: any = await beforeSubmit(values, viewRef.current);
        if (params === false) {
            return;
        }
        let {url, method, isMessBool = true} = props;
        let newParams = createParams(params, props);
        if (!isEdit()) {
            delete newParams.id;
        }
        if (!url) {
            if (props.unUrlIsFinish) {
                await closeModal(props.modalKey, async () => {
                    return {data: newParams};
                })
            }
            return false;
        }
        let methodType: string = method ? method : (isEdit() ? "PUT" : "POST");
        setLoading(true);
        let result: any = await AxiosSer(url, methodType, {
            ...newParams,
            [Config.axiosSerMenuKey]: props.menuId
        }, isMessBool) || {};
        setLoading(false);
        result.code == "1" && await closeModal(props.modalKey, async () => {
            return {data: newParams, ...result};
        });
    }, 2000, [props.modalKey, props.type, props.flowData, props.unUrlIsFinish, props.menuId]);

    const loadView: Function = useCallback(async (editData: any) => {
        const {view, dataSource}: { view: any, dataSource: any } = props;
        if (isString(view)) {
            let result = await getFormView(view, editData, dataSource);
            tryFunction(() => {
                eval("window.linkageForm =" + result.linkageControl)
                linkageRef.current = window.linkageForm || {};
            });
            if (result.form && linkageRef.current.beforeFormatView) {
                await tryFunctionAsync(async () => {
                    result.form = (await linkageRef.current.beforeFormatView.call(null, result.form, editData)) || [];
                })
            }
            if (result.form && props.formatFormView) {
                result.form = await props.formatFormView(result.form, editData);
            }
            setView(result.form);
        } else {
            setView((await getFormViewList(view, editData)).form);
        }
    }, [props]);

    const init: Function = useCallback(async () => {
        let editData = await getInitData();
        setEditData(editData);
        loadView(editData)
    }, [props.view, props.getInitData, props.menuId]);

    useEffect(() => {
        init();
    }, [props.view, props.getInitData]);

    useEffect(() => {
        addOkModal(props.modalKey, onOk);
    }, []);

    useImperativeHandle(props.init, () => {
        return {
            fromRef,
            onOk,
            formView: viewRef.current
        };
    });

    const renderCreateModal = useMemo(() => {
        const {formItemLayout, labelWidth, className = "", onRemoveView}: {
            formItemLayout: any,
            labelWidth: number,
            className?: string,
            onRemoveView?: Function
        } = props;
        if (!view || !view.length || !editData) {
            return <div style={{minHeight: 30}} className="spin-content"><Spin/></div>
        }
        return (
            <Spin spinning={loading} wrapperClassName={"sf_core_create_modal " + className}>
                <BaseForm
                    isDisabledForm={props.isDisabledForm}
                    init={fromRef}
                    labelWidth={labelWidth}
                    formItemLayout={formItemLayout}
                    view={view}
                    initValues={editData}
                    onValuesChange={onValuesChange}
                    onRemoveView={onRemoveView}
                >
                    {props.children}
                </BaseForm>
            </Spin>
        )
    }, [view, editData, loading, props]);

    return (renderCreateModal);
};

export default CreateModal;